home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 8: LINUX Games / Linux Cubed Series 8 - LINUX Games.iso / games / x11 / strategy / xpat2-1.000 / xpat2-1 / xpat2-1.04 / src / X-gfx2.c < prev    next >
C/C++ Source or Header  |  1994-10-03  |  25KB  |  817 lines

  1. /*****************************************************************************/
  2. /*                                         */
  3. /*                                         */
  4. /*    X patience version 2 -- module X-gfx2.c                     */
  5. /*                                         */
  6. /*    Alternate graphics interface for colour servers                 */
  7. /*    Requires the xpm library.                         */
  8. /*    written by Michael Bischoff (mbi@mo.math.nat.tu-bs.de)             */
  9. /*    March-1994                                 */
  10. /*    see COPYRIGHT.xpat2 for Copyright details                 */
  11. /*                                         */
  12. /*                                         */
  13. /*****************************************************************************/
  14. /* #define SAVE_IMAGES */
  15. #define ALLATONCE
  16. /* #define MIRRORING */
  17.  
  18. #include "X-pat.h"
  19. #include <time.h>
  20. #include <xpm.h>
  21.  
  22. #ifndef NO_ROUND_CARDS
  23. #include <X11/Xmu/Drawing.h>
  24. #endif
  25.  
  26. /* with this module, cards are built the following way:
  27.    1) If a complete card image does exist (filename: "(rank).(suit).xpm"),
  28.       this image is read and used as the card pixmap. A rounded rectangle
  29.       is drawn as a border. If the image does not exist, the card is
  30.       constructed as follows.
  31.    2) a white pixmap of full cardsize is created. The width and height
  32.       are taken from the Cards.conf file (1st line) and default to 79x123.
  33.    3) The default card background, taken from Background.xpm, is centered
  34.       in the pixmap.
  35.    4) Rank and small suit symbols are drawn into the pixmap.
  36.    5) If a center picture does exist (filename "(rank).(suit).pic.xpm"),
  37.       it is centered in the card. Otherwise, the card is filled with suit 
  38.       symbols.
  39.    6) A rounded rectangle is drawn as card border.
  40.  
  41.    For pictures (Jack to King), the procedure in 5) is slightly different,
  42.    as the center pictures have to be mirrored and drawn twice.
  43.  
  44.  
  45.    The cards may be configured by the Cards.conf file. This file is optional
  46.    and may end after any line. The values not read from the file take their
  47.    default values then.
  48.  
  49.    line | entries | comment, [default]
  50.    -----+---------+--------------------------------------------------------
  51.       1 |   2     | width, height of the cards    [79x123]
  52.       2 |   2     | number of cardbacks, jokers [1, 1]
  53.       3 |   1     | flags, bits are ored together, see below [0]
  54.       4 |   2     | x, y distance of the border lines for pictures [6, 7]
  55.       5 |   2     | Position of the medium-sized suit symbols for pictures
  56.         |         |   (0 = omit them)            [11, computed]
  57.       6 |   2     | x, y coordinate of the rank symbols [4,6]
  58.       7 |   2     | x, y coordinate of the small suit symbol below the rank
  59.         |         |   symbol                [3, computed]
  60.       8 |   2     | xdelta, ydelta amount in pixels to shift large symbols
  61.         |         |   closer together                   [0,0]
  62.       9 |   3     | x0,x1,x2 the three possible x-coordinates of the large
  63.         |         |   suit symbols            [computed]
  64.      10 |   9     | y0..y8 the nine possible y-coordinates of the large
  65.         |         |   suit symbols            [computed]
  66.    -----+---------+---------------------------------------------------------
  67.    Use of the lines 9 and 10 is intended for emergency cases only, as line
  68.    8 should allow all configurations with equidistant suit symbols.
  69. */
  70.  
  71. /* for flags: */
  72. #define TWORANKS    1    /* display two rank symbols? */
  73. #define PRINT        2    /* print x(i), y(i) (Debugging) */
  74. #define PIC_BG        4    /* use same background for pictures? */
  75. #define NOCENTERLINE    8    /* place picture one lower and don't draw black center line */
  76.  
  77. #define RANKWIDTH    9
  78. #define RANKHEIGHT    14
  79. #define SUITSIZE0    41
  80. #define SUITSIZE1    21
  81. #define SUITSIZE2    15
  82. #define SUITSIZE3    11
  83. #define SUITOFF0    (0)
  84. #define SUITOFF1    (SUITSIZE0)
  85. #define SUITOFF2    (SUITSIZE0+SUITSIZE1)
  86. #define SUITOFF3    (SUITSIZE0+SUITSIZE1+SUITSIZE2)
  87.  
  88. struct cardconfig {
  89.     int width, height;
  90.     int flags;
  91.     int ydelta;        /* odd integer! */
  92.     int Ox, Oy;        /* distance of the border for pictures */
  93.     int Rx, Ry;        /* position of the rank symbol */
  94.     int Sx, Sy;        /* position of the small suit symbol */
  95.     int Mx, My;        /* position of the medium suit symbol */
  96.     int x0, x1, x2;    /* x-positions of the large suit symbols */
  97.     int y0, y1, y2, y3, y4, y5, y6, y7, y8;    /* y-positions */
  98.     int numbacks, numjokers;
  99. } cc;
  100.  
  101.  
  102. static void read_cardconfig(const char *filename) {
  103.     FILE *fp;
  104.     int tmp[9];
  105.     if (!(fp = fopen(filename, "r")))
  106.     goto stdconfig;
  107.  
  108.     if (fscanf(fp, "%d %d", &CARD_WIDTH, &CARD_HEIGHT) != 2 ||
  109.     CARD_WIDTH < 49 || CARD_WIDTH > 123 ||
  110.     CARD_HEIGHT < 95 || CARD_HEIGHT > 200) {
  111.     fclose(fp);
  112.     fp = NULL;
  113.     goto stdconfig;
  114.     } else
  115.     goto havesize;
  116.  
  117.  stdconfig:
  118.     CARD_WIDTH = 79;
  119.     CARD_HEIGHT = 123;
  120.  havesize:
  121.     cc.numbacks = cc.numjokers = 1;
  122.     cc.ydelta = (((CARD_HEIGHT - 2 - 4 * SUITSIZE1) / 7) | 1);
  123.  
  124.     cc.x0 = (CARD_WIDTH - 1 * SUITSIZE1) / 2 - 2 * CARD_WIDTH / 9 + 1;
  125.     cc.x1 = (CARD_WIDTH - 1 * SUITSIZE1) / 2;
  126.     cc.x2 = (CARD_WIDTH - 1 * SUITSIZE1) / 2 + 2 * CARD_WIDTH / 9 - 1;
  127.  
  128.     cc.y0 = (CARD_HEIGHT - 3 * cc.ydelta - 4 * SUITSIZE1) / 2;
  129.     cc.y1 = (CARD_HEIGHT - 2 * cc.ydelta - 3 * SUITSIZE1) / 2;
  130.     cc.y2 = (CARD_HEIGHT - 1 * cc.ydelta - 2 * SUITSIZE1) / 2;
  131.     cc.y3 = (CARD_HEIGHT - 0 * cc.ydelta - 1 * SUITSIZE1) / 2;
  132.     cc.y4 = (CARD_HEIGHT + 1 * cc.ydelta - 0 * SUITSIZE1) / 2;
  133.     cc.y5 = (CARD_HEIGHT + 2 * cc.ydelta + 1 * SUITSIZE1) / 2;
  134.     cc.y6 = (CARD_HEIGHT + 3 * cc.ydelta + 2 * SUITSIZE1) / 2;
  135.     cc.y7 = (cc.y0 + cc.y3) / 2;
  136.     cc.y8 = (cc.y6 + cc.y3) / 2;
  137.  
  138.     cc.flags = 0;
  139.     cc.Mx = 11;
  140.     cc.My = cc.y0 + 3;
  141.     cc.Ox = 6;
  142.     cc.Oy = 7;
  143.     cc.Rx = 4;
  144.     cc.Ry = 6;
  145.     cc.Sx = 3;
  146.     cc.Sy = cc.y0 + SUITSIZE1 - SUITSIZE3;
  147.     if (fp) {    /* Cards.Conf does exist */
  148.     /* possibility to override the defaults */
  149.     if (fscanf(fp, "%d %d", tmp, tmp+1) == 2)
  150.         cc.numbacks = tmp[0], cc.numjokers = tmp[1];
  151.     if (fscanf(fp, "%d", tmp) == 1)
  152.         cc.flags = tmp[0];
  153.     if (fscanf(fp, "%d %d", tmp, tmp+1) == 2)
  154.         cc.Ox = tmp[0],    cc.Oy = tmp[1];
  155.     if (fscanf(fp, "%d %d", tmp, tmp+1) == 2)
  156.         cc.Mx = tmp[0],    cc.My = tmp[1];
  157.     if (fscanf(fp, "%d %d", tmp, tmp+1) == 2)
  158.         cc.Rx = tmp[0],    cc.Ry = tmp[1];
  159.     if (fscanf(fp, "%d %d", tmp, tmp+1) == 2)
  160.         cc.Sx = tmp[0],    cc.Sy = tmp[1];
  161.     if (fscanf(fp, "%d %d", tmp, tmp+1) == 2) {    /* xdelta and ydelta */
  162.         cc.x0 += tmp[0], cc.x2 -= tmp[0],
  163.         cc.y0 += 3 * tmp[1];
  164.         cc.y1 += 2 * tmp[1];
  165.         cc.y2 += 1 * tmp[1];
  166.         cc.y4 -= 1 * tmp[1];
  167.         cc.y5 -= 2 * tmp[1];
  168.         cc.y6 -= 3 * tmp[1];
  169.         tmp[1] = tmp[1] * 3 / 2;
  170.         cc.y7 += tmp[1];
  171.         cc.y8 -= tmp[1];
  172.     }
  173.     if (fscanf(fp, "%d %d %d", tmp, tmp+1, tmp+2) == 3)
  174.         cc.x0 = tmp[0],    cc.x1 = tmp[1], cc.x2 = tmp[2];
  175.     if (fscanf(fp, "%d %d %d %d %d %d %d %d %d", tmp, tmp+1, tmp+2, tmp+3,
  176.            tmp+4, tmp+5, tmp+6, tmp+7, tmp+8) == 9)
  177.         cc.y0 = tmp[0],    cc.y1 = tmp[1], cc.y2 = tmp[2],
  178.         cc.y3 = tmp[3],    cc.y4 = tmp[4], cc.y5 = tmp[5],
  179.         cc.y6 = tmp[6],    cc.y7 = tmp[7], cc.y8 = tmp[8];
  180.     fclose(fp);
  181.     }
  182.     if (cc.flags & PRINT)
  183.     printf("y = %d %d %d  %d %d %d  %d %d %d, x = %d %d %d\n",
  184.        cc.y0, cc.y1, cc.y2,
  185.        cc.y3, cc.y4, cc.y5,
  186.        cc.y6, cc.y7, cc.y8,
  187.        cc.x0, cc.x1, cc.x2);
  188.     return;
  189.  
  190. }
  191.  
  192. #define MAXJOKERS 4
  193.  
  194. static Pixmap card_map[60+MAXJOKERS], card_clip;
  195.  
  196. /* we use a 2-phase algorithm, a combination of two mirrors */
  197. /* the amount of data copied is greater, but there are far less calls to XCopyArea */
  198. static void MirrorCard(Drawable p, int w, int h) {
  199.     int x, y, H;
  200.     H = h/2;
  201.     /* first, build a left-right mirror */
  202.     for (x = 0; x < w; ++x)
  203.     XCopyArea(dpy, p, p, whitegc, x, 1, 1, H-1, w-1-x, H+2);
  204.     /* now mirror the lower half of the card upside-down */
  205.     for (y = 0; y < H/2; ++y) {
  206.     XCopyArea(dpy, p, p, whitegc, 0, h-1-y, w, 1, 0, H+1+y);
  207.     XCopyArea(dpy, p, p, whitegc, 0, H+2+y, w, 1, 0, h-1-y);
  208.     }
  209.     /* shift one scan line */
  210.     XCopyArea(dpy, p, p, whitegc, 0, H+2+H/2, w, H/2, 0, H+1+H/2);
  211.     
  212.     /* restore the bottom line which was overwritten */
  213.     XCopyArea(dpy, p, p, whitegc, 0, 0, w, 1, 0, h-1);
  214. }
  215.  
  216. static const char *xpmdir;
  217. static int mem_option;
  218. static GC cardbackgc;        /* gc in use when drawing cardbacks */
  219. static GC suitgc, rankgc;    /* gc in use when drawing suit and rank symbols */
  220. /* these have fixed clipmasks */
  221.  
  222. #include "logo.bm"
  223.  
  224. static void make_GCs(void) {
  225.     XGCValues gcv;
  226.     long gcflags;
  227.     Pixmap tmpmap;
  228.     Pixmap logomap;
  229.  
  230.     /* make GC for cardbacks */
  231.     tmpmap = XCreateBitmapFromData(dpy, RootWindow(dpy, screen),
  232.     logo_bits, logo_width, logo_height);
  233.     logomap = XCreatePixmap(dpy, RootWindow(dpy, screen),
  234.     logo_width, logo_height, DefaultDepth(dpy, screen));
  235.     
  236.     gcv.foreground = BlackPixel(dpy, screen);
  237.     gcv.background = WhitePixel(dpy, screen);
  238.     gcv.graphics_exposures = True;
  239.     gcflags = GCForeground | GCBackground | GCGraphicsExposures;
  240.     
  241.     cardbackgc = XCreateGC(dpy, RootWindow(dpy, screen), gcflags, &gcv);
  242.     suitgc = XCreateGC(dpy, RootWindow(dpy, screen), gcflags, &gcv);
  243.     rankgc = XCreateGC(dpy, RootWindow(dpy, screen), gcflags, &gcv);
  244. }
  245.  
  246.  
  247. static char *xpmname(const char *s, const char *ext) {
  248.     static char buff[200];
  249.     sprintf(buff, "%s/%s.%s", xpmdir, s, ext);
  250.     return buff;
  251. }
  252.  
  253.  
  254. void init_cards(const char *cardset, int rx, int ry,
  255.     unsigned long red, unsigned long cbcolor, int mem, const char *xpm) {
  256.     int i;
  257.  
  258.     for (i = 0; i < 58; ++i)
  259.     card_map[i] = 0;
  260.  
  261.     mem_option = mem;
  262.     make_GCs();
  263. #ifdef NO_ROUND_CARDS
  264.     rx = ry = 0;
  265. #endif
  266.     if (!xpm) {        /* we definitely need an xpmdir for this module */
  267.     char *s;
  268.     s = malloc(strlen(LIBDIR) + 10);
  269.     sprintf(s, "%s/default", LIBDIR);
  270.     xpmdir = s;
  271.     } else if (*xpm != '.' && *xpm != '/') {    /* supply path */
  272.     char *s;
  273.     s = malloc(strlen(LIBDIR) + strlen(xpm) + 2);
  274.     sprintf(s, "%s/%s", LIBDIR, xpm);
  275.     xpmdir = s;
  276.     }
  277.     
  278.     card.cardset = cardset;
  279.     /* build internal cardset */
  280.     read_cardconfig(xpmname("Cards", "conf"));
  281.  
  282.  
  283.     /* sanity checks: */
  284.     if (2 * rx >= (int)CARD_WIDTH)
  285.     rx = CARD_WIDTH / 2;
  286.     if (2 * ry >= (int)CARD_HEIGHT)
  287.     ry = CARD_HEIGHT / 2;
  288.     /* assign values */
  289.     if (rx >= 0)
  290.     card.rx = rx;
  291.     if (ry >= 0)
  292.     card.ry = ry;
  293.     
  294.  
  295.     ROUND_W = ROUND_H = 9;
  296.     STD_DELTA = cc.ydelta + SUITSIZE1;
  297.  
  298.     /* adapt arrows to match cardset sizes */
  299.     graphic.aw = graphic.ah = STD_DELTA / 6;
  300.     graphic.ya_h = graphic.xa_w = graphic.aw * 2;
  301.     graphic.xa_h = graphic.ya_w = graphic.aw * 4;
  302.  
  303.     /* finally, compute a clipping mask for the cards */
  304.     /* apply this clip mask to cardbackgc */
  305. #ifndef NO_ROUND_CARDS
  306. #ifndef STATIC_CLIPMAPS
  307.     if (ROUND_W) {
  308.     card_clip = XCreatePixmap(dpy, RootWindow(dpy, screen),
  309.                     CARD_WIDTH+1, CARD_HEIGHT+1, 1);
  310.     {    XGCValues    gcv;
  311.          long gcflags, f, b;
  312.          GC clipgc;
  313.          
  314.          b = 0;
  315.          f = 1;
  316.  
  317.          /* first, clear the clipmap */
  318.          /* (is it possible to do it easier?) */
  319.          gcv.foreground = b;
  320.          gcv.background = f;
  321.          gcv.graphics_exposures = False;
  322.          gcflags = GCForeground | GCBackground | GCGraphicsExposures;
  323.          clipgc = XCreateGC(dpy, card_clip, gcflags, &gcv);
  324.          XFillRectangle(dpy, card_clip, clipgc, 0, 0, 
  325.                 CARD_WIDTH, CARD_HEIGHT);
  326.          XFreeGC(dpy, clipgc);
  327.          
  328.          /* make gc for clipgc */
  329.          gcv.foreground = f;
  330.          gcv.background = b;
  331.          gcv.graphics_exposures = False;
  332.          gcflags = GCForeground | GCBackground | GCGraphicsExposures;
  333.          clipgc = XCreateGC(dpy, card_clip, gcflags, &gcv);
  334.          XmuFillRoundedRectangle(dpy, card_clip, clipgc, 0, 0, 
  335.              CARD_WIDTH-1, CARD_HEIGHT-1, ROUND_W, ROUND_H);
  336.          XmuDrawRoundedRectangle(dpy, card_clip, clipgc, 0, 0, 
  337.              CARD_WIDTH-1, CARD_HEIGHT-1, ROUND_W, ROUND_H);
  338.          XFreeGC(dpy, clipgc);
  339.      }
  340. #ifdef DEBUG
  341.     XWriteBitmapFile(dpy, "clip.mask.bm", card_clip, CARD_WIDTH, CARD_HEIGHT, -1, -1);
  342. #endif
  343.     /* fill the background */
  344.     XSetClipMask(dpy, cardbackgc, card_clip);
  345.     }
  346. #else
  347.     switch (ROUND_H) {
  348.     case 3:
  349.     case 4:
  350.     case 5:
  351.     card_clip = XCreateBitmapFromData(dpy, RootWindow(dpy, screen),
  352.         clip4_bits, clip4_width, clip4_height);
  353.     XSetClipMask(dpy, cardbackgc, card_clip);
  354.     break;
  355.     case 6:
  356.     case 7:
  357.     case 8:
  358.     case 9:
  359.     card_clip = XCreateBitmapFromData(dpy, RootWindow(dpy, screen),
  360.             clip7_bits, clip7_width, clip7_height);
  361.     XSetClipMask(dpy, cardbackgc, card_clip);
  362.     break;
  363.     }
  364. #endif
  365. #endif
  366. }
  367.  
  368. #ifdef SAVE_IMAGES
  369. static void write_xpmfile(char *filename, Pixmap pict, Pixmap clip) {
  370.     if (XpmWriteFileFromPixmap(dpy, filename, pict, clip, NULL) != XpmSuccess)
  371.         fprintf(stderr, "error writing xpm file %s\n", filename);
  372. }
  373. #endif
  374.  
  375. static struct picture {
  376.     int flag;
  377.     int w, h;
  378.     Pixmap map;
  379.     Pixmap clip;
  380. } big = { 0 }, bg = { 0 }, p_rank = { 0 }, p_suit = { 0 };
  381.  
  382.  
  383. static int read_xpmfile(const char *name, struct picture *p) {
  384.     XpmAttributes attribs;
  385.     attribs.valuemask = 0;
  386.     switch (XpmReadFileToPixmap(dpy, table, xpmname(name, "xpm"), &p->map, &p->clip, &attribs)) {
  387.     case XpmSuccess:
  388.     break;    /* yeah! */
  389.     case XpmColorError:
  390.     case XpmColorFailed:
  391.     fprintf(stderr, "xpm: Not enough colors.\n");
  392.     return p->flag = 0;
  393.     case XpmFileInvalid:
  394.     fprintf(stderr, "xpm: Invalid file.\n");
  395.     return p->flag = 0;
  396.     case XpmNoMemory:
  397.     fprintf(stderr, "xpm: Out of memory.\n");
  398.     return p->flag = 0;
  399.     case XpmOpenFailed:
  400.     default:
  401.     /* maybe not serious */
  402.     return p->flag = 0;
  403.     }
  404.     p->w = attribs.width;
  405.     p->h = attribs.height;
  406.     return p->flag = 1;
  407. }
  408.  
  409. static void free_picture(struct picture *p) {
  410.     XFreePixmap(dpy, p->map);
  411.     if (p->clip) XFreePixmap(dpy, p->clip);
  412.     p->flag = 0;
  413. }
  414.  
  415. static int overlap_picture(const char *name, int two, Pixmap d) {
  416.     struct picture p;
  417.     int x, y;
  418.  
  419.     if (!read_xpmfile(name, &p))
  420.     return 0;
  421.  
  422.     if (two) {
  423.     x = (CARD_WIDTH-p.w) / 2;
  424.     y = CARD_HEIGHT/2 - p.h;
  425.     if (cc.flags & NOCENTERLINE)
  426.         ++y;
  427.     } else {
  428.     x = (CARD_WIDTH-p.w) / 2;
  429.     y = (CARD_HEIGHT-p.h) / 2;
  430.     }
  431.     if (p.clip) {
  432.     XSetClipMask(dpy, whitegc, p.clip);
  433.     XSetClipOrigin(dpy, whitegc, x, y);
  434.     XCopyArea(dpy, p.map, d, whitegc, 0, 0, p.w, p.h, x, y);
  435.     XSetClipMask(dpy, whitegc, None);
  436.     } else
  437.     XCopyArea(dpy, p.map, d, whitegc, 0, 0, p.w, p.h, x, y);
  438.     
  439.     free_picture(&p);
  440.     return 1;
  441. }
  442.  
  443.  
  444.  
  445. /* suitflags: */
  446. /*  0 3 0
  447.       4
  448.     1 5 1     5 also 6 for asymmetric card (7) 
  449.  -- 2 7 2 -- */
  450.  
  451. /* rank symbols:
  452.    american: J, Q, K
  453.    german:   B, D, K
  454.    french:   V, D, R
  455.    old german: O, U, K
  456. */
  457.  
  458.  
  459.  
  460. #define PAINT_AT(xx, yy) {                    \
  461.     XSetClipOrigin(dpy, suitgc, (xx)-x, (yy)-SUITSIZE0);    \
  462.     XCopyArea(dpy, p_suit.map, d, suitgc, x,            \
  463.         SUITSIZE0, SUITSIZE1, SUITSIZE1, xx, yy);        \
  464. }
  465. #define PAINT_RV(xx, yy) {                     \
  466.     XSetClipOrigin(dpy, suitgc, (xx)-x, (yy)-SUITSIZE0);    \
  467.     XCopyArea(dpy, p_suit.map, d, suitgc, x,            \
  468.         SUITSIZE0, SUITSIZE1, SUITSIZE1, xx, yy);        \
  469. }
  470.  
  471.  
  472.  
  473. /* paint a (nearly) symmetric card */
  474. static void paint_large_1(Rank rank, Suit suit, Drawable d) {
  475.     static const unsigned char suitflags[] = {  /* 25 => 03 for different 8 */
  476.       0x80, 0x08, 0x88, 0x01, 0x81, 0x05, 0x45, 0x25, 0x83, 0x13, 0, 0, 0, 0 };
  477.     int x, y, cx, cy, dl;
  478.     char name[32];
  479.  
  480. #ifndef MIRRORING
  481.     if (cc.Rx) {
  482.     /* Draw the lower rank symbol(s). */
  483.     x = (8 + 3 * (suit/2) - (rank / 5)) * RANKWIDTH;
  484.     y = (4 - rank % 5) * RANKHEIGHT;
  485.     dl = CARD_WIDTH-RANKWIDTH;
  486.     cx = dl-cc.Rx;
  487.     cy = CARD_HEIGHT-cc.Ry-RANKHEIGHT;
  488.     if (p_rank.clip) XSetClipOrigin(dpy, rankgc, cx-x, cy-y);
  489.     XCopyArea(dpy, p_rank.map, d, rankgc, x, y, RANKWIDTH, RANKHEIGHT, cx, cy);
  490.     if (cc.flags & TWORANKS) {
  491.         cx = dl - cx;
  492.         if (p_rank.clip) XSetClipOrigin(dpy, rankgc, cx-x, cy-y);
  493.         XCopyArea(dpy, p_rank.map, d, rankgc, x, y, RANKWIDTH, RANKHEIGHT, cx, cy);
  494.     }
  495.     }
  496.     if (cc.Sx) {
  497.     /* Draw the lower small suit symbol(s). */
  498.     x = (suit+4) * SUITSIZE3;
  499.     y = SUITOFF3;
  500.     dl = CARD_WIDTH-SUITSIZE3;
  501.     cx = dl-cc.Sx;
  502.     cy = CARD_HEIGHT-cc.Sy-SUITSIZE3;
  503.     XSetClipOrigin(dpy, suitgc, cx-x, cy-y);
  504.     XCopyArea(dpy, p_suit.map, d, suitgc, x, y,
  505.           SUITSIZE3, SUITSIZE3, cx, cy);
  506.     if (cc.flags & TWORANKS) {
  507.         cx = dl - cx;
  508.         XSetClipOrigin(dpy, suitgc, cx-x, cy-y);
  509.         XCopyArea(dpy, p_suit.map, d, suitgc, x, y,
  510.               SUITSIZE3, SUITSIZE3, cx, cy);
  511.     }
  512.     }
  513. #endif
  514.  
  515.     /* load picture instead of standard symbols? */
  516.     sprintf(name, "%s.%s.pic", US_rank_name[rank], US_suit_name[suit]);
  517.     if (overlap_picture(name, 0, d))
  518.     return;
  519.  
  520.     /* OK, draw the suit symbols */
  521.     /* first, all symbols which are not mirrored */
  522.     x = SUITSIZE1 * suit;
  523.     if (suitflags[rank] & 0x01) {
  524.     PAINT_AT(cc.x0, cc.y0);
  525.     PAINT_AT(cc.x2, cc.y0);
  526.     }
  527.     if (suitflags[rank] & 0x02) {
  528.     PAINT_AT(cc.x0, cc.y2);
  529.     PAINT_AT(cc.x2, cc.y2);
  530.     }
  531.     if (suitflags[rank] & 0x08) {
  532.     PAINT_AT(cc.x1, cc.y0);
  533.     }
  534.     if (suitflags[rank] & 0x10) {
  535.     PAINT_AT(cc.x1, cc.y1);
  536.     }
  537.     if (suitflags[rank] & 0x20) {
  538.     PAINT_AT(cc.x1, cc.y7);
  539.     }
  540. #ifdef MIRRORING
  541.     MirrorCard(d, CARD_WIDTH, CARD_HEIGHT);
  542. #endif
  543.     if (suitflags[rank] & 0x04) {
  544.     PAINT_AT(cc.x0, cc.y3);
  545.     PAINT_AT(cc.x2, cc.y3);
  546.     }
  547.     if (suitflags[rank] & 0x40) {
  548.     PAINT_AT(cc.x1, cc.y7);
  549.     }
  550.     if (suitflags[rank] & 0x80) {
  551.     PAINT_AT(cc.x1, cc.y3);
  552.     }
  553. #ifdef MIRRORING
  554.     return;
  555. #endif
  556.     /* draw all symbols which are upside-down */
  557.     x = SUITSIZE1 * (suit+4);
  558.     if (suitflags[rank] & 0x01) {
  559.     PAINT_RV(cc.x0, cc.y6);
  560.     PAINT_RV(cc.x2, cc.y6);
  561.     }
  562.     if (suitflags[rank] & 0x02) {
  563.     PAINT_RV(cc.x0, cc.y4);
  564.     PAINT_RV(cc.x2, cc.y4);
  565.     }
  566.     if (suitflags[rank] & 0x08) {
  567.     PAINT_RV(cc.x1, cc.y6);
  568.     }
  569.     if (suitflags[rank] & 0x10) {
  570.     PAINT_RV(cc.x1, cc.y5);
  571.     }
  572.     if (suitflags[rank] & 0x20) {
  573.     PAINT_RV(cc.x1, cc.y8);
  574.     }
  575. }
  576.  
  577. /* paint a half card and mirror it */
  578. static void paint_large_2(Rank rank, Suit suit, Drawable d) {
  579.     int x, y;
  580.     if (cc.Mx > 0) {
  581.     x = cc.Mx;
  582.     y = cc.My;
  583.     /* if (suit != 2)
  584.        --y; */
  585.     XSetClipOrigin(dpy, suitgc, x-suit*SUITSIZE2, y-SUITOFF2);
  586.     XCopyArea(dpy, p_suit.map, d, suitgc, SUITSIZE2 * suit, SUITOFF2, SUITSIZE2, SUITSIZE2, x, y);
  587.     }
  588.     /* horizontal line in the midst of the card: */
  589.     if (!(cc.flags & NOCENTERLINE))
  590.     XDrawLine(dpy, d, blackgc, cc.Ox, CARD_HEIGHT/2, CARD_WIDTH-1-cc.Ox, CARD_HEIGHT/2);
  591.     if (cc.Oy)
  592.     XDrawLine(dpy, d, blackgc, 4 + RANKWIDTH + 1, cc.Oy, CARD_WIDTH - 1 - 4 - RANKWIDTH - 1, cc.Oy);
  593.     if (cc.Ox) {
  594.     XDrawLine(dpy, d, blackgc, cc.Ox,              cc.y7+1, cc.Ox,              CARD_HEIGHT/2);
  595.     XDrawLine(dpy, d, blackgc, CARD_WIDTH-1-cc.Ox, cc.y7+1, CARD_WIDTH-1-cc.Ox, CARD_HEIGHT/2);
  596.     }
  597.     {   /* load a card image */
  598.     if (big.flag == 1) {
  599.         /* have it! */
  600.         x = (CARD_WIDTH-big.w) / 2;
  601.         y = CARD_HEIGHT/2 - big.h;
  602.         if (cc.flags & NOCENTERLINE)
  603.         ++y;
  604.         XSetClipMask(dpy, whitegc, big.clip);
  605.         XSetClipOrigin(dpy, whitegc, x-big.w*suit, y-big.h*(rank-Jack));
  606.         XCopyArea(dpy, big.map, d, whitegc, big.w*suit, big.h*(rank-Jack), big.w, big.h, x, y);
  607.         XSetClipMask(dpy, whitegc, None);
  608.     } else {
  609.         char name[32];
  610.         sprintf(name, "%s.%s.pic", US_rank_name[rank], US_suit_name[suit]);
  611.         overlap_picture(name, 2, d);
  612.     }
  613.     }
  614.     MirrorCard(d, CARD_WIDTH, CARD_HEIGHT);
  615. }
  616.  
  617. static void read_images(void) {    
  618.     static int done = 0;
  619.     if (done)
  620.     return;
  621.     done = 1;
  622.  
  623.     if (read_xpmfile("Pictures", &big)) {
  624.     big.w /= 4;
  625.     big.h /= 3;
  626.     }
  627.     read_xpmfile("Background", &bg);
  628.     if (!read_xpmfile("Suits", &p_suit)) {
  629.     fprintf(stderr, "cannot read suits\n");
  630.     exit(1);
  631.     }
  632.     if (!read_xpmfile("Ranks", &p_rank)) {
  633.     fprintf(stderr, "cannot read ranks\n");
  634.     exit(1);
  635.     }
  636.     XSetClipMask(dpy, suitgc, p_suit.clip);
  637.     if (p_rank.clip) XSetClipMask(dpy, rankgc, p_rank.clip);
  638. }
  639.  
  640.  
  641. static void paint_large_card(Rank rank, Suit suit, Drawable d) {
  642.     int x, y;
  643.     /* make sure we have all pixmaps */
  644.  
  645.     if (rank > King) {    /* is a suit symbol for empty stack */
  646.     x = (CARD_WIDTH-SUITSIZE0)/2;
  647.     y = (CARD_HEIGHT-SUITSIZE0)/2;
  648.     XSetClipOrigin(dpy, suitgc, x-suit*SUITSIZE0, y);
  649.     XCopyArea(dpy, p_suit.map, d, suitgc, SUITSIZE0 * suit, 0,
  650.           SUITSIZE0, SUITSIZE0, x, y);
  651.     return;
  652.     }
  653.  
  654.     if (cc.Rx) {
  655.     /* Draw the upper rank symbol(s). */
  656.     x = 3 * (suit/2) * RANKWIDTH + (rank / 5) * RANKWIDTH;
  657.     y = (rank % 5) * RANKHEIGHT;
  658.     if (p_rank.clip) XSetClipOrigin(dpy, rankgc, cc.Rx-x, cc.Ry-y);
  659.     XCopyArea(dpy, p_rank.map, d, rankgc, x, y,
  660.           RANKWIDTH, RANKHEIGHT, cc.Rx, cc.Ry);
  661.     if (cc.flags & TWORANKS) {
  662.         if (p_rank.clip) XSetClipOrigin(dpy, rankgc, CARD_WIDTH-RANKWIDTH-cc.Rx-x, cc.Ry-y);
  663.         XCopyArea(dpy, p_rank.map, d, rankgc, x, y,
  664.               RANKWIDTH, RANKHEIGHT, CARD_WIDTH-RANKWIDTH-cc.Rx, cc.Ry);
  665.     }
  666.     }
  667.     if (cc.Sx) {
  668.     /* Draw the upper small suit symbol(s). */
  669.     x = cc.Sx;
  670.     y = cc.Sy;
  671.     XSetClipOrigin(dpy, suitgc, x-suit*SUITSIZE3, y-SUITOFF3);
  672.     XCopyArea(dpy, p_suit.map, d, suitgc, suit * SUITSIZE3, SUITOFF3,
  673.           SUITSIZE3, SUITSIZE3, x, y);
  674.     if (cc.flags & TWORANKS) {
  675.         x = CARD_WIDTH-SUITSIZE3 - cc.Sx;
  676.         XSetClipOrigin(dpy, suitgc, x-suit*SUITSIZE3, y-SUITOFF3);
  677.         XCopyArea(dpy, p_suit.map, d, suitgc, suit * SUITSIZE3, SUITOFF3,
  678.               SUITSIZE3, SUITSIZE3, x, y);
  679.     }
  680.     }
  681.     if (rank >= Jack)
  682.     paint_large_2(rank, suit, d);
  683.     else
  684.     paint_large_1(rank, suit, d);
  685. }
  686.  
  687. static Pixmap start_card(int c) {
  688.     Pixmap d;
  689.     d = XCreatePixmap(dpy, table, CARD_WIDTH, CARD_HEIGHT, DefaultDepth(dpy, screen));
  690.     XFillRectangle(dpy, d, whitegc, 0, 0, CARD_WIDTH-1, CARD_HEIGHT-1);
  691.  
  692.     /* draw the background, if non-picture */
  693.     if (bg.flag == 1 && ((cc.flags & PIC_BG) || !(RANK(c) >= Jack && RANK(c) <= King))) {
  694.     int x, y;
  695.     x = (CARD_WIDTH-bg.w)/2;
  696.     y = (CARD_HEIGHT-bg.h)/2;
  697.     if (bg.clip) {   
  698.         XSetClipMask(dpy, whitegc, bg.clip);
  699.         XSetClipOrigin(dpy, whitegc, x, y);
  700.         XCopyArea(dpy, bg.map, d, whitegc, 0, 0, bg.w, bg.h, x, y);
  701.         XSetClipMask(dpy, whitegc, None);
  702.     } else
  703.         XCopyArea(dpy, bg.map, d, whitegc, 0, 0, bg.w, bg.h, x, y);
  704.     }
  705.     return d;
  706. }
  707.  
  708. static void finish_card(int c, Pixmap d) {
  709.     /* 6) A rounded rectangle is drawn as card border. */
  710. #ifndef NO_ROUND_CARDS
  711.     if (ROUND_W)
  712.         XmuDrawRoundedRectangle(dpy, d,
  713.             blackgc, 0, 0, CARD_WIDTH-1, CARD_HEIGHT-1, ROUND_W, ROUND_H);
  714.     else
  715. #endif
  716.         XDrawRectangle(dpy, d, blackgc, 0, 0, CARD_WIDTH-1, CARD_HEIGHT-1);
  717. }
  718.  
  719.  
  720. static void get_card(int c) {
  721.     /* try to load card image from xpm file */
  722.     char name[200];
  723.     read_images();
  724.     if (c >= 52) {
  725.     if (c == CARDBACK) {
  726.         sprintf(name, "Cardback%d", 1 +
  727.             (int)(game.seed & 0xfff) % cc.numbacks);
  728.     } else if (c >= JOKER) {
  729.         sprintf(name, "Joker%d", 1 + ((c - JOKER) + (int)((game.seed / cc.numbacks) & 0xfff))
  730.             % cc.numjokers);    /* use all different jokers, starting at rnd position */
  731.     } else
  732.         *name = '\0';
  733.     } else
  734.     sprintf(name, "%s.%s", US_rank_name[RANK(c)],
  735.         US_suit_name[SUIT(c)]);
  736.  
  737.     card_map[c] = start_card(c);
  738.     if (*name && overlap_picture(name, 0, card_map[c])) {
  739.     /* has map, just draw a rounded rectangle as border around it */
  740.     finish_card(c, card_map[c]);
  741.     return;
  742.     }
  743.     if (c >= 56) {
  744.     fprintf(stderr, "cannot read %s\n", name);
  745.     exit(1);
  746.     }
  747.  
  748.     /* OK, we have to create it ourselves. */
  749.     /* 2) a white pixmap of full cardsize is created. The width and height
  750.           are taken from the Cards.conf file (1st line) and default to 79x123. */
  751.     /* basic initialisation */
  752.     paint_large_card(RANK(c), SUIT(c), card_map[c]);
  753.     finish_card(c, card_map[c]);
  754.  
  755. #ifdef SAVE_IMAGES
  756.     if (*name)
  757.     write_xpmfile(name, card_map[c], 0);
  758. #endif
  759. }
  760.  
  761. void PaintCard(int x, int y, int c, int delta) {
  762.     
  763. #ifdef ALLATONCE
  764.     static int loaded = 0;
  765.     if (!loaded) {
  766.     int i;
  767.     loaded = 1;
  768.     /* show_message(TXT_LOADING);
  769.     XSync(dpy, 0); */
  770.     /* read all the cards we need in any case. Do not read */
  771.     /* Cardbacks or Jokers, they are possibly not needed */
  772.     /* printf("before read_images: %ld\n", time(NULL)); */
  773.     read_images();
  774.     for (i = 0; i < 56; ++i) {
  775.         /* if (!(i&3)) printf("before card %d: %ld\n", i, time(NULL)); */
  776.         get_card(i);
  777.     }
  778.     /* printf("after cards are contructed: %ld\n", time(NULL)); */
  779.     /* show_message(TXT_WELCOME, VERSION); */
  780.     if (big.map)
  781.         free_picture(&big);
  782.     free_picture(&p_rank);
  783.     free_picture(&p_suit);
  784.     }
  785. #endif
  786.  
  787.  
  788.     if (c == NOTHING)
  789.     /* return; */
  790.     goto outline;    /* this is better */
  791.     /* JOKERs not yet fully implemented */
  792.     if (IS_JOKER(c))
  793.     c = JOKER + (c-JOKER) % MAXJOKERS;
  794.     if (c != OUTLINE) {
  795.     if (!card_map[c])
  796.         /* must make cardmap */
  797.         get_card(c);
  798.     delta += ROUND_H;
  799.     if (delta == ROUND_H || delta > CARD_HEIGHT)
  800.         delta = CARD_HEIGHT;
  801.     XSetClipOrigin(dpy, cardbackgc, x, y);
  802.     XCopyArea(dpy, card_map[c], table, cardbackgc, 0, 0, CARD_WIDTH, delta, x, y);
  803.     return;
  804.     }
  805.  outline:
  806.     /* if (c == OUTLINE) */
  807.     /* to be sure the place is clear: */
  808.     XClearArea(dpy, table, x, y, CARD_WIDTH, CARD_HEIGHT, False);
  809. #ifndef NO_ROUND_CARDS
  810.     if (ROUND_W)
  811.     XmuDrawRoundedRectangle(dpy, table, blackgc, x, y,
  812.        CARD_WIDTH-1, CARD_HEIGHT-1, ROUND_W, ROUND_H);
  813.     else
  814. #endif
  815.     XDrawRectangle(dpy, table, blackgc, x, y, CARD_WIDTH-1, CARD_HEIGHT-1);
  816. }
  817.